/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package biofilter.filters;

import biofilter.exceptions.InvalidRecordException;
import biofilter.records.GFFRecord;
import biofilter.records.Record;
import biofilter.records.HistogramRecord;
import biofilter.records.ScoredRegionRecord;
import biofilter.util.MappedPosition;

/**
 * This filter takes as input a region file containing positions (e.g. a GFF file)
 * and a histogram representing an expression profile.
 * The output is a new set of mapped positions, each with a score coresponding to
 * a normalized percent of the expression profile that overlaps the position.
 * @author Daniel Quest
 * @date   April 8 2010
 *
 */
public class ScoreRegionsFMHistoFilter extends SimpleFilter {  //note this should be a join filter... but base class does not exist
    
    private HistogramRecord hr;
    public ScoreRegionsFMHistoFilter(HistogramRecord h){
        hr = h;
    }
    
    public ScoreRegionsFMHistoFilter(HistogramRecord h, String gapToken, String geneToken){
        this.gapToken = gapToken;
        this.geneToken = geneToken;
    }

    public HistogramRecord getHr() {
        return hr;
    }

    public void setHr(HistogramRecord hr) {
        this.hr = hr;
    }

    /**
     * By default minReadLength is used to filter regions that have a number of consecutive basepairs
     * with value 0 or less.
     *
     * for example, consider 2 regions A, and B.
     * A contains a largest gap that is 20bp long.
     * B contains a largest gap that is 36bp long.
     * Reads from the technology are known to be 35bp in length. (current default)
     *
     * Logically, it is possible that region A has the gap because no read was sequenced
     * at the positions covering the gap... so we should ignore such a gap.
     *
     * However, by the same logic region B, may not actually have any reads that cover the gap
     * in the sample... so we should throw this region out as 'not enough data'.
     */
    private int minReadLength = 35;
    public int getMinReadLength() {
        return minReadLength;
    }

    public void setMinReadLength(int minReadLength) {
        this.minReadLength = minReadLength;
    }
    
    /**
     * 
     * @param required coverage serves to eliminate regions from the later analysis
     * that do not have enough data to confirm structure of the transcription unit.
     * 
     * This is done in a similar way to minReadLength, in that at this point records
     * are just going to be flagged as not having enough data... later we can
     * do something with them.
     */
    private double requiredCoverage = 0.5;
    public double getRequiredCoverage() {
        return requiredCoverage;
    }

    public void setRequiredCoverage(double requiredCoverage) {
        this.requiredCoverage = requiredCoverage;
    }
    
    private String gapToken = "GAP";  //The gap token is the GFF name given to the regions filled.
    private String geneToken = "CDS"; //Token used to determine if the region is a gene/coding sequence.
    public String getGapToken() {
        return gapToken;
    }

    public void setGapToken(String gapToken) {
        this.gapToken = gapToken;
    }

    public String getGeneToken() {
        return geneToken;
    }

    public void setGeneToken(String geneToken) {
        this.geneToken = geneToken;
    }


    @Override
    protected Record transformRecord(Record r) throws InvalidRecordException {
        ScoredRegionRecord sr = new ScoredRegionRecord();
        GFFRecord gff = (GFFRecord) r;
        //CORRECTION, THE FOLLOWING CODE ASSUMES THAT THE GFF MATCHES THE REPLICON...
        //if the current histogram does not mach the gff record currently flowing by,
        //then we need to move on to another record
        //if(!gff.getSubjectID().equalsIgnoreCase(hr.getTarget())){
        //    r = this.getRecord();
        //}
        sr.setGFF(gff);
        sr.scoreRegion(hr);
        double score = sr.getAverageOverRegion();
        sr.setScore(score);
        sr.get();
        /**
         * Set INSUFFICENTDATA Flags as needed.
         */
        if (sr.getLongestGap() >= this.minReadLength ){ sr.setFlagValue(ScoredRegionRecord.Flag.INSUFFICENTDATA); }
        else if (sr.getAverageOverRegion() < this.requiredCoverage){ sr.setFlagValue(ScoredRegionRecord.Flag.INSUFFICENTDATA); }
        else if ( sr.isType(this.geneToken) ){ sr.setFlagValue(ScoredRegionRecord.Flag.GENE); }
        else if ( sr.isType(this.gapToken) && sr.getMinOverRegion() > 0){ sr.setFlagValue(ScoredRegionRecord.Flag.COVEREDGAP); }
        else if ( sr.isType(this.gapToken) ){ sr.setFlagValue(ScoredRegionRecord.Flag.UNCOVEREDGAP); }

        return sr;
    }

    public Record peek() throws InvalidRecordException {
        throw new UnsupportedOperationException("Not supported yet.");
    }


}
